#ifndef TYPE_TRAITS_H
#define TYPE_TRAITS_H

#include <complex>
#include <type_traits>
#include <iterator>

/**
 *  @brief  type traits to check if T is a std::complex type
 */
template <class T>
struct is_complex
{
	static constexpr bool value = false;
};

template <>
template <typename T2>
struct is_complex< std::complex<T2> >
{
	static constexpr bool value = true;
};

/**
 *  @brief  type traits to check if T supports bitwise copy
 *  
 *  T supports bitwise copy if T is arithmetic type or std::complex
 *  or POD type.
 */
template <typename T>
struct type_check
{
	static constexpr bool support_bitwise_op = 
		std::is_arithmetic<T>::value ||
		is_complex<T>::value ||
		std::is_pod<T>::value;
};

/**
 *  @brief  type traits to check if both iter1 ant iter2 are random access iterators
 */
template <class iter1, class iter2>
struct two_iter_check
{
	typedef typename std::iterator_traits<iter1>::iterator_category  iter_type_1;
	typedef typename std::iterator_traits<iter2>::iterator_category  iter_type_2;
	static constexpr bool both_random = 
		std::is_same<iter_type_1, std::random_access_iterator_tag>::value && 
		std::is_same<iter_type_2, std::random_access_iterator_tag>::value;
};

/**
 *  @brief  multi-component type traits
 */
template <class T>
struct multi_component_traits
{
	typedef T component_type;
	static constexpr unsigned int num_components = 0;
};

template <class T2, unsigned int N> class tiny_vector;

template <>
template <class T2, unsigned int N>
struct multi_component_traits< tiny_vector<T2, N> >
{
	typedef T2 component_type;
	static constexpr unsigned int num_components = N;
};

template <>
template <class T2>
struct multi_component_traits< std::complex<T2> >
{
	typedef T2 component_type;
	static constexpr unsigned int num_components = 2;
};

#endif //< TYPE_TRAITS_H